<template>
	<!-- 左右纵向列表联动页面 -->
	<!-- 参考链接：https://blog.csdn.net/Chanyto/article/details/131994786 -->
	<view style="display: flex;flex-direction: column;height: 100%;">
		<!-- 顶部面板 -->
		<view>
			<!-- 顶部面板，可添加所需要放在页面顶部的内容代码。比如banner图 -->
			<view style="background-color: #ffaa00;text-align: center;font-size: 28rpx;padding: 10px 0;color: #fff;">
				<view>这里顶部内容占位区域，不需要则删除</view>
				<view>可添加需放在页面顶部的内容，比如banner、轮播图等</view>
			</view>
		</view>
		<!-- 滚动区域 -->
		<view class="scroll-panel" id="scroll-panel" style="flex-grow: 1;display: block;">
			<view class="list-box">
				<view class="left">
					<scroll-view scroll-y="true" :style="{ 'height':scrollHeight + 'px' }"
						:scroll-with-animation="false">
						<view class="item" v-for="(item,index) in cateData" :key="index"
							:class="{ 'active':index===leftIndex }" :id="'left-'+index" @tap="leftTap(index)">
							{{item.name}}
						</view>
					</scroll-view>
				</view>
				<view class="main">
					<scroll-view scroll-y="true" :style="{ 'height':scrollHeight + 'px' }" @scroll="mainScroll"
						:scroll-into-view="scrollInto" :scroll-with-animation="false">
						<view class="item main-item" v-for="(item,index) in cateName" :key="index" :id="'item-'+index"
							@tap="click">
							<view class="title">
								<view>cateName{{index}}</view>
							</view>
							<view class="goods" v-for="(item2,index2) in listData" :key="index2">
								<image :src="item2.logo" mode=""></image>
								<view>
									<view>item2.name {{index}}</view>
									<view class="describe">item2.subname {{index}}</view>
								</view>
							</view>
						</view>
						<view class="fill-last" :style="{ 'height':fillHeight + 'px' }"></view>
					</scroll-view>
				</view>
			</view>
		</view>
	</view>

</template>
​
<script>
	export default {
		data() {
			return {
				scrollHeight: 400, // 默认高度
				scrollTopSize: 0, // 默认顶部高度
				fillHeight: 0, // 填充高度，用于最后一项低于滚动区域时使用
				topArr: [], // 左侧列表元素
				leftIndex: 0, // 点击切换存储的下标
				scrollInto: '', // 左侧定位
				cateData: [{
					"name": "category1"
				}, {
					"name": "category2"
				}, {
					"name": "category3"
				}],
				cateName: [1, 2, 3],
				listData: [1, 2, 3, 4, 5, 6, 7]

			}
		},
		onReady() {
			this.initScrollView()
			this.getElementTop()
		},
		methods: {
			/* 初始化滚动区域 */
			initScrollView() {
				return new Promise((resolve, reject) => {
					let view = uni.createSelectorQuery().select('#scroll-panel');
					view.boundingClientRect(res => {
						this.scrollTopSize = res.top;
						this.scrollHeight = res.height;
						setTimeout(() => {
							resolve();
						}, 100);
					}).exec();
				});
			},
			// 获取右边数据
			async onRightListFetch() {
				const res = await this.$store.dispatch("tool/getToolList", {

				});
				if ([100].includes(res.code)) {
					this.listTotal = res.result.tltal
					this.listData = res.result.data || []
					let map = new Map();
					for (let item of this.listData) {
						map.set(item.cateId, item);
					}
					this.cateName = [...map.values()].sort((a, b) => {
						return a.cateId - b.cateId
					});
					this.$nextTick(() => {
						this.getElementTop()
						this.initScrollView()
					})
				} else {
					this.$toast(res.msg);
				}
			},
			// 获取左边数据
			async onLeftListFetch() {
				const res = await this.$store.dispatch('tool/getCateList')
				if ([100].includes(res.code)) {
					this.cateTotal = res.result.total
					this.cateData = res.result.data.sort((a, b) => {
						return a.id - b.id
					}) || []
					this.loading = false
				} else {
					this.$toast(res.msg)
				}
			},
			/* 获取元素顶部信息 */
			getElementTop() {
				new Promise((resolve, reject) => {
					let view = uni.createSelectorQuery().selectAll('.main-item');
					view.boundingClientRect(data => {
						resolve(data);
					}).exec();
				}).then((res) => {
					console.log('res', res);
					let topArr = res.map((item) => {
						return item.top - this.scrollTopSize; /* 减去滚动容器距离顶部的距离 */
					});
					this.topArr = topArr;
					/* 获取最后一项的高度，设置填充高度。判断和填充时做了 +-20 的操作，是为了滚动时更好的定位 */
					let last = res[res.length - 1].height;
					if (last - 20 < this.scrollHeight) {
						this.fillHeight = this.scrollHeight - last + 20;
					}
				});
			},
			/* 主区域滚动监听 */
			mainScroll(e) {
				// console.log("mainscroll:", JSON.stringify(e))
				// 节流方法
				clearTimeout(this.mainThrottle);
				this.mainThrottle = setTimeout(this.scrollFn(e), 10);
			},

			scrollFn(e) {
				/* 查找当前滚动距离 */
				for (var i = this.topArr.length - 1; i >= 0; --i) {
					if ((e.detail.scrollTop + 2) >= this.topArr[i]) {
						if (this.leftIndex === i) {
							break
						} else {
							this.leftIndex = i
						}
						// index = i;
						//(index < 0 ? 0: index);
						break;
					}
				}
			},

			/* 左侧导航点击 */
			leftTap(e) {
				this.leftIndex = e
				this.scrollInto = "item-" + e;
			}
		}
	}
</script>
​
<style lang="scss">
	page {
		height: 100%;
	}

	.list-box {
		display: flex;
		flex-direction: row;
		flex-wrap: nowrap;
		justify-content: flex-start;
		align-items: flex-start;
		align-content: flex-start;
		font-size: 28rpx;

		.left {
			width: 200rpx;
			background-color: #f6f6f6;
			line-height: normal;
			box-sizing: border-box;
			font-size: 32rpx;

			.item {
				padding: 30rpx;
				position: relative;


				&+.item {
					margin-top: 1px;

					&::after {
						content: '';
						display: block;
						height: 0;
						border-top: #d6d6d6 solid 1px;
						width: 620upx;
						position: absolute;
						top: -1px;
						right: 0;
						transform: scaleY(0.5);
						/* 1px像素 */
					}
				}

				&.active {
					color: #42b983;
					background-color: #fff;
					position: relative;

					&::before {
						content: '';
						display: block;
						position: absolute;
						top: 0;
						left: 0;
						border-left: #42b983 solid 4px;
						height: 100%;
						width: 0;
					}
				}
			}

			.fill-last {
				height: 0;
				width: 100%;
				background: none;
			}
		}

		.main {
			background-color: #fff;
			padding-left: 20rpx;
			width: 0;
			flex-grow: 1;
			box-sizing: border-box;



			.title {
				line-height: normal;
				padding: 30rpx 0;
				font-size: 24rpx;
				font-weight: bold;
				color: #666;
				background-color: #fff;
				position: sticky;
				top: 0;
				z-index: 19;
			}

			.item {
				padding-bottom: 16rpx;
				border-bottom: #eee solid 1px;
			}

			.goods {
				display: flex;
				flex-direction: row;
				flex-wrap: nowrap;
				justify-content: flex-start;
				align-items: center;
				align-content: center;

				&+.goods {
					margin-top: 16rpx;
				}

				&>image {
					width: 120rpx;
					height: 120rpx;
					margin-right: 16rpx;
					margin-left: 2px;
				}

				.describe {
					font-size: 24rpx;
					color: #999;
				}

				.money {
					font-size: 24rpx;
					color: #efba21;
				}
			}
		}
	}
</style>